﻿/*
Copyright (c) 2010 Lance Ward
This software is licensed under the MIT license, except where otherwise noted.
For complete license details, refer to license.txt
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using ADNLib;

namespace ADNCanvas
{
	public enum DrawingToolType
	{
        AnimPointer,
        AnimPointEdit,
        AnimPath,
		Pointer,
		PointEdit,
		Rectangle,
		Ellipse,
		Line,
		Bezier,
		Text,
		Freehand,
		Spray,
		Pattern,
        RightTriangle,
        IsoscelesTriangle,
        Pentagon,
        Hexagon,
        Octagon,
        Parallelogram,
        Trapezoid,
        FivePointStar,
        SixPointStar,
		Clone,
		Shadow,
		Undefined
	}

	public enum ToolMode
	{
		Adding,
		Boxing,		//selecting via a selection rectangle
		Moving,
		None,
		Sizing,
		Rotating
	}

	public class ToolEventArgs : EventArgs
	{
		private Cursor toolCursor = Cursors.Default;
		private bool forcePaint = false;

		public ToolEventArgs() { }
		public ToolEventArgs(bool isComplete)
		{
			IsComplete = IsComplete;
		}

		public Cursor ToolCursor
		{
			get { return toolCursor; }
			set { toolCursor = value; }
		}

		public bool ForcePaint 
		{
			get { return forcePaint; }
			set { forcePaint = value; } 
		}
		public bool IsComplete { get; set; }
	}

	public class Tool
	{
		protected ToolMode mode = ToolMode.None;
        protected ToolSelectorMode selMode = ToolSelectorMode.None;
		protected DrawingToolType toolType = DrawingToolType.Undefined;
		protected XColor defaultFill;
		protected XColor defaultLine;
		protected Shape currentShape;
		protected PointF prevPoint;

		protected List<XObject> xObjects;
		protected List<XObject> selObjects;
		protected Graphics parentSurface;

		public event EventHandler<ToolEventArgs> ShapeComplete;	//both send true to indicate complete. Should never send anything else
		public event EventHandler<ToolEventArgs> ToolComplete;
		public event EventHandler<ToolEventArgs> CursorChange;
		public event EventHandler<ToolEventArgs> Refresh;
        public event EventHandler SelectionChanged;

		public DrawingToolType ToolType
		{
			get { return toolType; }
			set { toolType = value; }
		}

		public Shape CurrentShape
		{
			get { return currentShape; }
		}

		public XColor DefaultFill
		{
			get { return defaultFill; }
			set { defaultFill = value; }
		}

		public XColor DefaultLine
		{
			get { return defaultLine; }
			set { defaultLine = value; }
		}

		public virtual RectangleF EraseRect
		{
			get { return GetEraseArea(); }
		}

        public ToolMode Mode
        {
            get { return mode; }
            set { mode = value; }
        }

        public ToolSelectorMode SelectorMode
        {
            get { return selMode; }
            set { selMode = value; }
        }

		public List<XObject> XObjects
		{
			get { return xObjects; }
			set { xObjects = value; }
		}

		public virtual List<XObject> SelectedObjects
		{
			get { return selObjects; }
			set { selObjects = value; }
		}

		public Graphics ParentSurface
		{
			set { parentSurface = value; }
		}

		private RectangleF GetEraseArea()
		{
			//gets the largest possible rectangle of the shape path and previous point.
			RectangleF rect = new RectangleF();
			
			if (currentShape != null)
			{
				rect = currentShape.Bounds;
				PointF start = new PointF(rect.Left, rect.Top);
				PointF end = new PointF(rect.Right, rect.Bottom);

				if (prevPoint.X < start.X) { start.X = prevPoint.X; }
				if (prevPoint.Y < start.Y) { start.Y = prevPoint.Y; }
				if (prevPoint.X > end.X) { end.X = prevPoint.X; }
				if (prevPoint.Y > end.Y) { end.Y = prevPoint.Y; }

				rect.Inflate(20, 20);
			}

			return rect;
		}

		public virtual void MouseDown(PointF location, MouseButtons button, int clicks) { }
		public virtual void MouseMove(PointF location, MouseButtons button, int clicks) { }
		public virtual void MouseUp(PointF location, MouseButtons button, int clicks) { }
		public virtual void MouseDoubleClick(PointF location, MouseButtons button, int clicks) { }
		public virtual void OnKeyDown(char keyChar, Keys modifiers, bool capsLock) { }

		public virtual Cursor GetToolCursor() { return Cursors.Default; }

		protected virtual void OnShapeComplete(bool isComplete)
		{
			EventHandler<ToolEventArgs> handler = ShapeComplete; //per MS, copied to local to avoid race condition
			if (handler != null) 
			{ 
				handler(this, new ToolEventArgs(true));
				currentShape = null;
			}
		}

		protected virtual void OnToolComplete(bool isComplete)
		{
			EventHandler<ToolEventArgs> handler = ToolComplete; //per MS,  copied to local to avoid race condition
			if (handler != null) { handler(this, new ToolEventArgs(true)); }
		}

		protected virtual void OnCursorChange(Cursor cursor)
		{
			ToolEventArgs args = new ToolEventArgs();
			args.ToolCursor = cursor;

			EventHandler<ToolEventArgs> handler = CursorChange; //per MS,  copied to local to avoid race condition
			if (handler != null) { handler(this, args); }
		}

		protected virtual void OnRefresh(bool forcePaint)
		{
			ToolEventArgs args = new ToolEventArgs();
			args.ForcePaint = forcePaint;

			EventHandler<ToolEventArgs> handler = Refresh; //per MS,  copied to local to avoid race condition
			if (handler != null) { handler(this, args); }
		}

        protected void OnSelectionChanged()
        {
            if (SelectionChanged != null) { SelectionChanged(this, EventArgs.Empty); }
        }

		protected int HitTestObjects(PointF p)
		{
			if (xObjects != null)
			{
				for (int i = xObjects.Count - 1; i >= 0; i--)
				{
					if (xObjects[i].HitTest(parentSurface, p))
					{
						return i; 
					}
				}
			}

			return -1;
		}

        protected int HitTestObjects(PointF p, Type objType)
        {
            if (xObjects != null)
            {
                for (int i = xObjects.Count - 1; i >= 0; i--)
                {
                    if (xObjects[i].HitTest(parentSurface, p) && xObjects[i].GetType() == objType)
                    {
                        return i;
                    }
                }
            }

            return -1;
        }
	}
}
